/*
+ 轻量级图文编辑器
+ 作者：蒲子明
+ 版本：1.0.0
+ 日期：2020年9月22日
* */

(function(){
    function Editor(id,option){
        this.Init(id,option);
    }
    //暴露对象给全局
    window.emEditor = Editor;
    'use strict';
    //全局常量

    //公共内部函数
    //判断对象类型
    let utils = {};
    ['String', 'Function', 'Array', 'Number', 'RegExp', 'Object', 'Date'].forEach(v=>{
        utils['is' + v] = function(obj){
            return Object.prototype.toString.apply(obj) === '[object ' + v + ']';
        }
    });
    utils.isEmptyObject = (obj)=>{
        if (obj == null) return true;
        if (utils.isArray(obj) || utils.isString(obj)) return obj.length === 0;
        for (var key in obj) if (obj.hasOwnProperty(key)) return false;
        return true;
    };

    //多个对象深度复制，以属性类型相等为原则进行添加
    function extend(t) {
        for (let i = 1; i < arguments.length; i++) {
            let obj = arguments[i]||{};
            for (let k in obj) {
                if (!t.hasOwnProperty(k)){
                    //没有这个属性，直接复制上，如果禁止添加多余
                    t[k] = obj[k];
                }else {
                    if (utils.isObject(obj[k]) && utils.isObject(t[k])){
                        extend(t[k],obj[k]);
                    }else if(obj[k].constructor === t[k].constructor){
                        t[k] = obj[k];
                    }
                }
            }
        }
        return t;
    }
    //1、创建元素
    function createElement(elm,cls,style,txt,parent){
        var elm = document.createElement(elm||'div');
        if (cls) elm.className = cls;
        if (style){
            elm.style.cssText = style;
        }
        if (txt){
            elm.innerText = txt;
        }
        parent && parent.appendChild(elm);
        return elm;
    }
    function remove(obj) {
        obj.parentNode.removeChild(obj);
    }
    function getIndex(obj) {
        return [].indexOf.call(obj.parentNode.childNodes,obj);
    }
    function getBlockElement(obj){
        if (obj){
            if (['DIV','SECTION','P','LI','PRE'].indexOf(obj.nodeName) >= 0){
                return obj;
            }
            return getBlockElement(obj.parentNode);
        }
        return null;
    }
    //2、绑定事件
    function on(dom, type, fun) {
        if (dom.addEventListener) {
            dom.addEventListener(type, fun, false);
        } else if (dom.attachEvent) {
            dom.attachEvent("on" + type, fun);
        } else {
            var maps = dom._handlers || (dom._handlers = {});
            maps[type] = (maps[type] || []).concat(fun);
        }
    }
    //3、解绑事件
    function off(dom, type, fun) {
        if (dom.removeEventListener) {
            dom.removeEventListener(type, fun, false);
        } else if (dom.detachEvent) {
            dom.detachEvent("on" + type, fun);
        } else {
            var maps = dom._handlers, arr = maps && maps[type];
            if (arr) {
                var index = indexOf(arr, fun);
                if (index > -1)
                { maps[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }
            }
        }
    }
    //ajax
    function ajax(json){
        let me = this;
        json = extend({type: 'GET',dataType: 'json'},json);
        if (!json.url) return;
        json.data = json.data || {};

        let data = '',
            urlChar = '?';
        for(let key in json.data){
            data += urlChar + key + '=' + json.data[key];
            urlChar = '&';
        }
        json.url += data;
        //创建Request对象
        let xhr = new XMLHttpRequest()
        //xhr.withCredentials = false;
        if (json.type.toUpperCase() == 'POST'){
            xhr.open('POST', json.url, true);
            // 如果需要像 html 表单那样 POST 数据，请使用 setRequestHeader() 来添加 http 头。
            //xhr.setRequestHeader('Content-type', json.formData?'multipart/form-data':'application/x-www-form-urlencoded');
            //设置header参数
            if (json.header){
                for(let key in json.header){
                    xhr.setRequestHeader(key, json.header[key]);
                }
            }
            xhr.send(json.formData);
        }else{
            xhr.open('GET', json.url, true);
            //设置header参数
            if (json.header){
                for(let key in json.header){
                    xhr.setRequestHeader(key, json.header[key]);
                }
            }
            xhr.send();
        }

        //监听进度事件
        xhr.addEventListener('progress', function (e) {
            //百分比
            let percent = e.lengthComputable ?　Math.round(e.loaded / e.total * 100) : 0;
            utils.isFunction(json.progress) && json.progress.call(me,e,percent);
        }, false);

        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4 && xhr.status === 200) {
                if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
                    let res = '',
                        rt = xhr.responseText;
                    if(rt.length>0){
                        res = json.dataType==='json'?JSON.parse(rt):rt;
                    }
                    utils.isFunction(json.success) && json.success(res);
                } else {
                    utils.isFunction(json.error) && json.error(xhr.status);
                }
            }
        };
    }
    function setCssStyle(editor) {
        if (!editor.document._useStyleWithCSS) {
            editor.document.execCommand('styleWithCSS', null, true);
            editor.document._useStyleWithCSS = true;
        }
        return true;
    }
    //创建弹窗
    function createPopup(editor,style,html,confirm,noClose){
        if (editor.popup) remove(editor.popup);
        editor.popup = createElement('','popup scrollbar',style);
        editor.popup.innerHTML = html;
        on(editor.popup,'click',function (e) {
            utils.isFunction(confirm) && confirm.call(e,editor);
            if (!noClose){
                remove(editor.popup);
                editor.popup = null;
            }
        });
        editor.container.appendChild(editor.popup);
    }
    //创建独占窗口
    function createDialog(editor,title,style,parms,buttons){
        let mask = createElement('','dialogmask','','',editor.container),
            dialog = createElement('','dialog',style,''),
            titlebar = createElement('','titlebar','','',dialog);
        function closeDailog(){
            remove(mask);
            remove(dialog);
            editor.dialog = null;
        }
        createElement('p','title','',title,titlebar);
        let closeBtn = createElement('','closebtn','',title);
        closeBtn.innerHTML = '<div class="closeicon"></div>';
        on(closeBtn,'click',closeDailog);
        titlebar.appendChild(closeBtn);
        //dialog主界面
        let dialogMain = createElement('','main','','',dialog);
        //dialog页脚
        if (utils.isArray(buttons)){
            let footer = createElement('','footer','','');
            for(let i=0;i<buttons.length;i++){
                let btn = createElement('button','',buttons[i].style,buttons[i].title);
                if (utils.isFunction(buttons[i].click)){
                    on(btn,'click',buttons[i].click);
                }
                if (buttons[i].close){
                    on(btn,'click',closeDailog);
                }
                footer.appendChild(btn);
            }
            dialog.appendChild(footer);
        }
        editor.container.appendChild(dialog);
        //处理个性化参数
        parms = extend({center:true},parms);
        if (parms.center){
            dialog.style.left = ((editor.container.offsetWidth - dialog.offsetWidth) / 2) +'px';
            dialog.style.top = ((editor.container.offsetHeight - dialog.offsetHeight) / 2) +'px';
        }
        utils.isFunction(parms.onInit) && parms.onInit.call(dialogMain);
        return dialogMain;
    }
    function menuEnabled(icon){
        return icon.firstChild.classList.contains('enabled');
    }
    //创建菜单图标
    function createIcon(item,editor){
        let icon = item.icon = createElement('','iconbox');
        item.data && icon.setAttribute('data',item.data);
        icon.setAttribute('title',item.title);
        icon.innerHTML = '<svg class="icon enabled" aria-hidden="true"><use xlink:href="#icon-'+item.name+'"></use></svg>';
        if (item.file){
            if (editor.wx && item.accept && item.accept.indexOf('image')>=0){
                //微信图片选择
                on(icon,'click',()=>{
                    menuEnabled(icon) && wx.chooseImage({
                        count: item.file==='multiple'?9:1,
                        sizeType: ['original', 'compressed'],
                        sourceType: ['album', 'camera'],
                        success (res) {
                            let imgs = [];
                            res.localIds.forEach(item=>{
                                imgs.push({src:item,title:item});
                            });
                            insertImage(editor,imgs);
                        }
                    })
                });
                (item.accept.indexOf('audio')>=0) && on(icon,'click',()=>{
                    menuEnabled(icon) && wx.chooseImage({
                        count: item.file==='multiple'?9:1,
                        sizeType: ['original', 'compressed'],
                        sourceType: ['album', 'camera'],
                        success (res) {
                            let imgs = [];
                            res.localIds.forEach(item=>{
                                imgs.push({src:item,title:item});
                            });
                            insertImage(editor,imgs);
                        }
                    })
                });
            }else{
                //选择文件按钮
                icon.style.position = 'relative';
                let input = createElement('input');
                input.setAttribute('type','file');
                (item.file==='multiple') && input.setAttribute('multiple',true);
                item.accept && input.setAttribute('accept',item.accept);
                on(input,'change',function (e) {
                    item.change.call(e,editor);
                });
                icon.appendChild(input);
            }
        }else{
            //不选择文件模式
            item.event = item.event || 'click';
            on(icon,item.event,function(){
                menuEnabled(icon) && (item[item.event]||iconClick).call(this,editor);
            });
        }
        (item.event !== 'mouseenter') && on(icon,'mouseenter',function(){
            if (editor.popup){
                remove(editor.popup);
                editor.popup = null;
            }
        });
        return icon;
    }
    //正常html样式设置按钮
    function iconClick(editor){
        let cmd = this.getAttribute('data'),
            icon = editor.activeIcons[cmd],
            clsName = 'activeicon';
        if (icon){
            if (editor.emData.iconGroup.indexOf(cmd) >= 0){
                editor.emData.iconGroup.forEach(item=>{
                    cmd===item?editor.activeIcons[cmd].classList.add(clsName):editor.activeIcons[item].classList.remove(clsName);
                })
            }else{
                icon.classList.contains(clsName)?icon.classList.remove(clsName):icon.classList.add(clsName);
            }
        }
        cmd && setCssStyle(editor) && editor.document.execCommand(cmd,false,true);
    }
    //字体大小
    function iconFontSize(editor){
        let style = 'left:'+this.offsetLeft+'px;top:'+(this.offsetTop+30)+'px;width:150px;max-height:80%;';
        let html = '<ul class="activeitem">',
            sizes = {1:10,2:12,3:16,4:18,5:24,6:32,7:48};
        for(let k in sizes){
            html += '<li style="font-size:'+sizes[k]+'px;" data="'+k+'">'+sizes[k]+'px</li>';
        }
        html += '</ul>';
        createPopup(editor,style,html,function () {
            if (this.target.nodeName === 'LI'){
                setCssStyle(editor);
                editor.document.execCommand('FontSize',false,this.target.getAttribute('data'));
            }
            remove(editor.popup);
            editor.popup = null;
        })
    }
    //颜色选择框
    function colorList(editor){
        let html = '';
        editor.emData.colors.split('|').forEach((item,i)=>{
            let margin = (i<10 || (i>49 && i<60))?'margin-bottom:8px;':'';
            html += '<div class="color" title="#'+item+'" style="background-color:#'+item+';'+margin+'"></div>';
        });
        return html;
    }
    //字体颜色
    function iconFontColor(editor) {
        let left = this.offsetLeft,
            width = editor.container.offsetWidth;
        if (left + 230 > width) left = width - 234;
        let style = 'left:'+left+'px;top:'+(this.offsetTop+30)+'px;width:230px;height:174px;';
        createPopup(editor,style,colorList(editor),function () {
            if (this.target.classList.contains('color')){
                setCssStyle(editor);
                editor.document.execCommand('ForeColor',false,this.target.style.backgroundColor);
            }
        })
    }
    //背景颜色
    function iconBackColor(editor) {
        let left = this.offsetLeft,
            width = editor.container.offsetWidth;
        if (left + 230 > width) left = width - 234;
        let style = 'left:'+left+'px;top:'+(this.offsetTop+30)+'px;width:230px;height:174px;';
        createPopup(editor,style,colorList(editor),function () {
            if (this.target.classList.contains('color')){
                setCssStyle(editor);
                editor.document.execCommand('BackColor',false,this.target.style.backgroundColor);
            }
        })
    }
    //插入图片
    function insertImage(editor,images){
        let html = '';
        images.forEach(item=>{
            html += '<p style="text-align: center"><img';
            for (let key in item){
                html += ' '+ key + '="'+item[key]+'"'
            }
            html += ' style="max-width:100%;"/></p><p><br/></p>';
        });
        editor.body.focus();
        editor.document.execCommand('insertHtml',false,html);
    }
    //插入视频
    function insertVideo(editor){
        let file = this.target.files,
            reader = new FileReader();
        reader.onload = (event)=>{
            editor.body.focus();
            editor.document.execCommand('insertHtml',false,'<p style="text-align:center"><video src="'+event.target.result+'" controls="controls" style="max-width:100%;">您的浏览器不支持 video 标签。</video></p><p><br/></p>');
        }
        reader.readAsDataURL(file[0]);
    }
    //直接选择文件上传
    function iconInsertImage(editor){
        let files = this.target.files,
            index = 0,
            base64 = [];
        function readFile(){
            const reader = new FileReader();
            reader.onload = (event) => {
                base64.push({src:event.target.result,title:files[index].name});
                index ++;
                if (index < files.length){
                    readFile();
                }else{
                    insertImage(editor,base64);
                }
            };
            reader.readAsDataURL(files[index]);
        }
        if (files.length) readFile();
    }
    //设置链接
    function iconSetLink(editor){
        let input = null;
        createDialog(editor,'添加链接','width:300px;height:112px;left:'+(editor.mainDiv.offsetWidth-300)/2+'px;top:200px;',{
            onInit: function(){
                input = createElement('input','txtinput','','');
                input.setAttribute('placeholder','请输入链接地址');
                this.appendChild(input);
            }
        },[{title:'确定',close:true,click:function(){
            let v = input.value.trim();
            if (v){
                editor.document.execCommand('CreateLink',false,v);
            }
            }},{title:'取消',close:true}])
    }
    //表格行列选择面板
    function iconSetTable(editor) {
        let left = this.offsetLeft,
            width = editor.container.offsetWidth,
            count = 10;
        if (left + 230 > width) left = width - 234;
        let style = 'left:'+left+'px;top:'+(this.offsetTop+30)+'px;width:230px;height:230px;',
            html = '<table class="menutable">';
        for(let i=0;i<count;i++){
            html += '<tr>';
            for(let j=0;j<count;j++){
                html += '<td></td>';
            }
            html += '</tr>';
        }
        html += '</table>';
        let row = -1,
            col = -1;
        createPopup(editor,style,html,function () {
            if (row >= 0 && col >= 0){
                let h = '<table style="width: 100%;height: auto;border-collapse: collapse;">';
                for(let i=0;i<=row;i++){
                    h += '<tr>';
                    for(let j=0;j<=col;j++){
                        h += '<td style="border: 1px solid black;">&nbsp;</td>';
                    }
                    h += '</td>';
                }
                editor.body.focus();
                editor.document.execCommand('insertHtml',false,h + '</table>');
            }
        });
        on(editor.popup.firstChild,'mousemove',function(e){
            if (e.target.nodeName === 'TD'){
                let r = getIndex(e.target.parentNode),
                    c = getIndex(e.target);
                if (row !== r || col !== c){
                    for (let i=0;i<count;i++){
                        for(let j=0;j<count;j++){
                            this.rows[i].cells[j].style.backgroundColor = (i<=r && j<=c)?'#00D1B2':null;
                        }
                    }
                    row = r;
                    col = c;
                }
            }
        })
    }
    //获取顶层section
    function getSection(obj) {
        if (!obj) return null;
        if (obj.nodeType !==1) return null;
        let parent = obj.parentNode;
        if (parent && (parent.tagName==='BODY' || (parent.classList && parent.classList.contains('bg')))) return obj;
        return getSection(parent);
    }
    Editor.prototype = {
        Init: function (id,option) {
            this.container = document.getElementById(id);
            this.container.classList.add('emeditor');
            this.container.innerHTML = null;

            this.settings = {
                menu: {
                    except: [],
                    newSVG: '',
                    newIcon: []
                }
            };
            //传入参数处理
            extend(this.settings,option);
            this.emData = window.emData;
            this.emData.svg && document.body.insertAdjacentHTML("afterBegin",emData.svg+this.settings.menu.newSVG+'</svg>');
            this.emData.svg = '';
            let toolbar = createElement('','menubar');

            this.container.appendChild(toolbar);
            this.popup = null;
            //编辑器主窗体，div内套iframe，同时放置绝对定位的图片、section编辑界面
            this.mainDiv = createElement('','main');
            //创建iframe
            this.iframe = createElement('iframe','scrollbar');
            this.iframe.frameBorder = 0;
            this.iframe.width = '100%';
            this.iframe.height = '100%';
            this.mainDiv.appendChild(this.iframe);
            this.container.appendChild(this.mainDiv);
            this.textarea = null;

            this.wx = window.__wxjs_environment === 'miniprogram';
            this.document = this.iframe.contentDocument;
            this.document.open();
            this.document.write(emData.html);
            this.document.close();
            this.activeIcons = {};
            this.window = this.document.defaultView || this.document.parentWindow;
            //菜单图标
            this.SetMenuEvent('save','click',()=>{this.Save({},()=>{})});
            this.SetMenuEvent('fontsize','mouseenter',iconFontSize);
            this.SetMenuEvent('fontcolor','mouseenter',iconFontColor);
            this.SetMenuEvent('backcolor','mouseenter',iconBackColor);
            this.SetMenuEvent('indent','click',()=>{
                let range=this.document.createRange?this.window.getSelection():this.document.selection.createRange();
                if (range.focusNode) {
                    let p = getBlockElement(range.focusNode);
                    if (p) p.style.textIndent = '2em';
                }
            });
            this.SetMenuEvent('outdent','click',()=>{
                let range=this.document.createRange?this.window.getSelection():this.document.selection.createRange();
                if (range.focusNode) {
                    let p = getBlockElement(range.focusNode);
                    if (p) p.style.textIndent = '0em';
                }
            });
            this.SetMenuEvent('link','click',iconSetLink);
            this.SetMenuEvent('table','mouseenter',iconSetTable);
            this.SetMenuEvent('pic','change',iconInsertImage);
            this.SetMenuEvent('croppic','change',function () {
                if (window.__wxjs_environment === 'miniprogram'){
                    console.log('miniprogram');

                }else{
                    console.log('no');
                }
            });
            this.SetMenuEvent('video','change',insertVideo);
            this.SetMenuEvent('code','click',()=> {
                let enabled = true;
                if (this.textarea){
                    this.SetContent(this.textarea.value);
                    remove(this.textarea);
                    this.textarea = null;
                    this.iframe.style.display = null;
                }else{
                    this.textarea = createElement('textarea','scrollbar','width:100%;height:100%;resize:none;',this.GetContent(),this.mainDiv);
                    this.iframe.style.display = 'none';
                    this.sectionPanel && this.sectionPanel.Hide();
                    this.imagePanel && this.imagePanel.Hide();
                    enabled = false;
                }
                this.emData.icons.forEach(item=>{
                    if (item.name !== 'code'){
                        this.SetMenuEnabled(item.name,enabled);
                    }
                });
            });
            this.settings.menu.newIcon.forEach(item=>{
                this.emData.icons.splice(utils.isNumber(item.index)?item.index:this.emData.icons.length,0,item);
            });
            this.emData.icons.forEach(item=>{
                if (this.settings.menu.except.indexOf(item.name) < 0){
                    let icon = createIcon(item,this);
                    if (this.emData.activeIcons.indexOf(item.data) >= 0){
                        this.activeIcons[item.data] = icon;
                    }
                    toolbar.appendChild(icon);
                }
            });
            //内容区
            this.body = this.document.body;
            this.body.innerHTML = localStorage.getItem('emEditor')||this.settings.content||'<p><br/></p>';
            // 设置元素为可编辑
            this.body.designMode = 'on';  //打开设计模式
            this.body.contentEditable = true;// 设置元素为可编辑
            //增加iframe编辑鼠标抬起事件，控制菜单按钮、section、img编辑等
            on(this.body,'mouseup',(e)=>{
                for (let key in this.activeIcons){
                    this.document.queryCommandState(key)?this.activeIcons[key].classList.add('activeicon'):this.activeIcons[key].classList.remove('activeicon');
                }
            });
            on(this.body,'click',(e)=>{
                let tag = e.target;
                if (tag){
                    if (tag.nodeName === 'IMG'){
                        this.sectionPanel && this.sectionPanel.Hide();
                        if(!this.imagePanel) this.imagePanel = new ImagePanel(this);
                        this.imagePanel.target = e.target;
                        this.imagePanel.AttachTo(e.target);
                    }else{
                        //section图文判断
                        this.imagePanel && this.imagePanel.Hide();
                        let elm = getSection(e.target);
                        if (elm){
                            if (!this.sectionPanel) this.sectionPanel = new Section(this);
                            this.sectionPanel.AttachTo(elm,this.sectionPanel.target !== elm);
                        }else{
                            this.sectionPanel && this.sectionPanel.Hide();
                        }
                    }
                }
            });
            let href = location.href;
            if (this.wx){
                let wxConfig = this.settings.wxConfig;
                //配置微信小程序编辑环境
                if (wxConfig){
                    ajax({url:wxConfig.url,
                        data:Object.assign({url:encodeURIComponent(href.split('#')[0])},wxConfig.data),
                        success:(config)=>{
                            config.debug = false;
                            config.jsApiList = ['chooseImage','getLocalImgData','uploadImage'];
                            wx.config(config);
                            /*
                            wx.ready((res)=>{
                                alert(res);
                            });
                            wx.error((res)=>{alert('111'+res)});*/
                        }
                    });
                }
            }
            let ajaxConfig = this.settings.ajaxConfig;
            if (utils.isObject(ajaxConfig)){
                let tokens = href.split('#');
                if (ajaxConfig.token) {
                    //获取token
                    let token = '';
                    for(let i=1;i<tokens.length;i++){
                        token += tokens[i];
                    }
                    ajaxConfig.token.value = token;
                }
                if (ajaxConfig.urlParm){
                    //处理url传递参数
                    let urlParm = tokens[0].split('?')[1];
                    if (urlParm){
                        let parmArray = urlParm.split('&'),
                            urlParmKeys = ajaxConfig.urlParm.split('|'),
                            tokenParmKeys = (ajaxConfig.tokenParm||'').split('|');
                        ajaxConfig.urlData = {};
                        for(let i=0;i<parmArray.length;i++){
                            let ps = parmArray[i].split('=');
                            if (urlParmKeys.indexOf(ps[0]) >= 0) ajaxConfig.urlData[ps[0]] = ps[1]||'';
                            if (tokenParmKeys.indexOf(ps[0]) >= 0) ajaxConfig.token.data[ps[0]] = ps[1]||'';
                        }
                    }
                }
                if (ajaxConfig.open){
                    //直接打开指定参数的图文
                    this.Ajax({url: ajaxConfig.open.url||ajaxConfig.url,
                                    dataType: 'text',
                                    data: extend(ajaxConfig.open.data,ajaxConfig.urlData),success:(res)=> {
                            this.SetContent(decodeURIComponent(res));
                        }
                    });
                }
            }
        },
        SetContent: function(html){
            this.body.innerHTML = html;
        },
        SetMenuEnabled: function(name,enable){
            let item = this.emData.icons.find(f=>{return f.name===name});
            if (item && item.icon){
                let cls = ['disabled'],
                    icon = item.icon.firstChild,
                    lastChild = item.icon.lastChild;
                enable?cls.push('enabled'):cls.splice(0,0,'enabled');
                icon.classList.remove(cls[0]);
                icon.classList.add(cls[1]);
                if (lastChild.nodeName === 'INPUT'){
                    enable?lastChild.removeAttribute('disabled'):lastChild.setAttribute('disabled','disabled');
                }
            }
        },
        SetMenuEvent: function(name,event,fun){
            //菜单事件设置
            let item = this.emData.icons.find(f=>{return f.name===name});
            if (item){
                item.event = event;
                item[event] = fun;
                return true;
            }
            return false;
        },
        Ajax:function(json){
            let me = this,
                now = new Date(),
                ajaxConfig = me.settings.ajaxConfig || {};
            if (ajaxConfig.token){
                json.header = json.header || {};
                json.header[ajaxConfig.token.headerKey||'token'] = ajaxConfig.token.value;
                if (!ajaxConfig.tokenTime || (now - ajaxConfig.tokenTime > (ajaxConfig.timeOut||7190)*1000)){
                    //重新获取token
                    ajax({url:ajaxConfig.token.url||ajaxConfig.url,
                        dataType:'text',
                        header: {token: ajaxConfig.token.value},
                        data:ajaxConfig.token.data,success:(res)=> {
                            ajaxConfig.tokenTime = now;
                            json.header[ajaxConfig.token.headerKey || 'token'] = ajaxConfig.token.value = res;
                            ajax(json);
                        }
                    });
                }else{
                    ajax(json);
                }
            }else{
                ajax(json);
            }
        },
        InsertImage: function(imgs){
            insertImage(this,imgs);
        },
        InsertHtml: function(html){
            this.document.execCommand('insertHtml',false,html);
        },
        ShowDialog: function(title,style,obj,buttons){
            this.dialog = createDialog(this,title,style,obj,buttons);
        },
        MessageBox(msg,title){
            this.dialog = createDialog(this,title||'提示','width:240px;height:auto;',{
                onInit:function(){
                    createElement('p','','padding:10px;',msg,this);
                }
            },[{title:'确定',close:true}]);
        },
        GetContent: function(){
            return this.body.innerHTML;
        },
        Save: function (parm,success) {
            let me = this,
                imgs = me.body.querySelectorAll('img'),
                ajaxConfig = me.settings.ajaxConfig,
                base64Imgs = [],
                imageFiles = [],
                index = 0,
                count = 0,
                ajaxUpload = (img,base64,fun)=>{
                    let formData = new FormData();
                    formData.append('image',base64);
                    me.Ajax({
                        type: 'POST',
                        dataType: 'text',
                        url: ajaxConfig.upbase64.url||ajaxConfig.url,
                        data: extend(ajaxConfig.upbase64.data||{},ajaxConfig.urlData||{},parm||{}),
                        formData,
                        success:(res)=>{
                            fun.call(me,img,res);
                        }
                    });
                },
                uploadBase64 = function(img){
                    if (img) {
                        ajaxUpload(img,img.src,(imgElement,url)=>{
                            if (url){
                                imgElement.src = url;
                                count ++;
                            }
                            index ++;
                            uploadBase64(base64Imgs[index]);
                        });
                    }else{
                        index = 0;
                        uploadWxFile(imageFiles[index]);
                    }
                },
                uploadWxFile = function (file) {
                    if (file) {
                        //经测试微信api接口可以读取base64
                        wx.getLocalImgData({
                            localId: file.src, // 图片的localID
                            success: function (res) {
                                //res.localData是图片的base64数据，可以用img标签显示
                                ajaxUpload(file,res.localData,(imgElement,url)=>{
                                    if (res){
                                        imgElement.src = url;
                                        count ++;
                                    }
                                    index ++;
                                    uploadWxFile(imageFiles[index]);
                                });
                            }
                        });
                        /*
                        alert('@@' + file.src);
                        wx.uploadImage({
                            localId: file.src,     // 需要上传的图片的本地ID，由chooseImage接口获得
                            isShowProgressTips: 1, // 默认为1，显示进度提示
                            success: function (res) {
                                //var serverId = res.serverId; // 返回图片的服务器端ID
                                alert(serverId+' '+res);
                            }
                        });*/
                    } else {
                        //存盘txt文件
                        let content = me.body.innerHTML;
                        if (content !== me.settings.content){
                            if (ajaxConfig.save){
                                let formData = new FormData();
                                formData.append('content',encodeURIComponent(content));
                                me.Ajax({
                                    type: 'POST',
                                    dataType: 'text',
                                    url: ajaxConfig.save.url||ajaxConfig.url,
                                    data: extend(ajaxConfig.save.data||{},ajaxConfig.urlData||{},parm||{}),
                                    formData,
                                    success:(res)=>{
                                        if (res > 0) {
                                            me.MessageBox('保存成功！');
                                            me.settings.content = content;
                                        }
                                    }
                                });
                            }else{
                                localStorage.setItem('emEditor',encodeURIComponent(content));
                                me.settings.content = content;
                                me.MessageBox('保存本地成功！');
                            }
                        }
                        utils.isFunction(success) && success.call(me, count);
                    }
                };
            imgs.forEach(item=>{
                //判断是否base64
                if (item.src.substr(0,9)==='weixin://'){
                    imageFiles.push(item);
                }else if (item.src.substr(0,11)==='data:image/'){
                    base64Imgs.push(item);
                }
            });
            uploadBase64(base64Imgs[index]);
        }
    }
    //Tab选项卡控件
    function Tab(id,options) {
        this.Init(id,options);
    }
    window.emTab = Tab;
    Tab.prototype = {
        Init: function (id,options) {
            let me = this;
            me.container = utils.isString(id)?document.getElementById(id):id;
            me.container.classList.add('emtab');
            me.settings = extend({tabpane:[],selectIndex:0},options);
            //tab标题栏
            let tabBar = createElement('ul','tabbar');
            me.settings.tabpane.forEach((item,index)=>{
                let li = createElement('li','',item.style,item.title,tabBar);
                item.hasOwnProperty('id') && li.setAttribute('data',item.id);
                utils.isFunction(item.change) && on(li,'click',function(){
                    me.SelectIndex(index);
                    item.change.call(me,index,this.getActiveAttrib('data'));
                });
            });

            utils.isFunction(me.settings.change) && on(tabBar,'click',function(e){
                if (e.target.nodeName === 'LI'){
                    let index = [].indexOf.call(tabBar.childNodes,e.target);
                    me.SelectIndex(index);
                }
            });
            me.container.appendChild(tabBar);
            //tabpage主体
            me.pages = createElement('','pages',me.settings.pagesStyle,'',me.container);
            me.SelectIndex(me.settings.selectIndex,true);
        },
        SelectIndex: function(index, force){
            let me = this;
            if (force || (index >= 0) && (index !== me.settings.selectIndex)){
                let nodes = me.container.firstChild.childNodes,
                    pane = me.settings.tabpane,
                    oldPage = pane[me.settings.selectIndex].page,
                    newPage = pane[index].page;
                nodes[me.settings.selectIndex].classList.remove('selected');
                nodes[index].classList.add('selected');
                me.settings.selectIndex = index;
                //创建页
                if (oldPage) oldPage.style.display = 'none';
                if (newPage){
                    newPage.style.display = null;
                }else{
                    let currentPane = pane[index];
                    currentPane.page = createElement('','page scrollbar',pane.pageStyle,pane.text,this.pages);
                    on(currentPane.page,'scroll',function (e) {
                        let tag = e.target,
                            scale = tag.offsetHeight / tag.scrollHeight;
                        if (!currentPane.scrollBegin && (tag.scrollTop+tag.offsetHeight) * scale + 10 > tag.offsetHeight){
                            currentPane.scrollBegin = true;
                            !currentPane.end && me.settings.change.call(me,me.settings.selectIndex,nodes[me.settings.selectIndex].getAttribute('data'));
                        }
                    });
                    on(pane[index].page,'dblclick',function (e) {
                        utils.isFunction(me.settings.selectRes) && me.settings.selectRes.call(me,e);
                    });
                }
                utils.isFunction(me.settings.change) && me.settings.change.call(me,index,nodes[index].getAttribute('data'))
            }
        },
        Ajax: function (index,success,error) {
            let me = this,
                pane = me.settings.tabpane[index],
                url = pane.url||me.settings.url;
            if (!url) return false;
            pane.beginNum = pane.beginNum || 0;
            pane.countNum = pane.countNum || 20;
            ajax({url,
                data:{ty:'editorres',classify:index,beginnum:pane.beginNum,countnum:pane.countNum},
                success: function(res){
                    utils.isFunction(success) && success.call(this,index,res);
                    pane.beginNum += res.length;
                    if (res.length < pane.countNum) pane.end = true;
                },
                error: function (f) {
                    console.log(f);
                }
            });
            return true;
        },
        addRes: function (index,res,webUrl,html,url) {
            html = html || 'html';
            url = url || 'url';
            let pane = this.settings.tabpane[index];
            res.forEach(item=>{
                let elm = null;
                if (item[html]){
                    elm = createElement('','elm','width:100%;max-width:640px;margin-bottom:8px;');
                    elm.innerHTML = decodeURIComponent(item.html);
                }else{
                    elm = createElement('img','pic','width:100%;max-width:'+(index==0?128:(index==2?320:192))+'px;margin:0px 8px 8px 0px;');
                    elm.src = webUrl + item[url];
                }
                pane.page.appendChild(elm);
            });
        }
    };
    /*图片调整面板
    * 作者：蒲子明，最后更新时间：20201019
    * V1.0.0
    */
    function ImagePanel(editor,options){
        this.Init(editor,options);
    }
    window.ImagePanel = ImagePanel;
    ImagePanel.prototype = {
        Init: function(editor, options){
            let me = this;
            me.editor = editor;
            me.doc = document;
            me.dragId = -1;
            //背面遮罩
            me.cover = createElement('','cover','','',editor.mainDiv);
            on(me.cover,'mousedown',()=>{me.Hide();});
            //图片尺寸调整框
            me.resizer = createElement('','resizer');
            let spans = '';
            for (let i = 0; i < 8; i++) {
                spans += '<div class="hand hand' + i + '"></div>';
            }
            me.resizer.innerHTML = spans;
            //图片调整框拖拽事件，为保证图片缩放保持比例，因此只调整width，为保证显示比例在不同机器上的通用，采用百分比模式
            on(me.resizer, 'mousedown',(e)=>{
                let tag = e.target;
                if (!tag || tag.nodeName !== 'DIV' || !tag.classList.contains('hand')) return;
                let index = e.target.className.slice(-1),
                    valX = [-1,0,1,-1,1,-1,0,1],
                    valY = [-1,-1,-1,0,0,1,1,1],
                    posX = e.clientX,
                    posY = e.clientY,
                    parent = me.target.parentNode,
                    width = parent.offsetWidth,
                    styleWidth = parseInt(me.target.style.width)||me.target.offsetWidth / width,
                    mouseMoveX = function (event) {
                        let newWidth = event.clientX - posX;
                        me.target.style.width = (styleWidth + newWidth / width * valX[index]*100) + '%';
                        me.AttachTo();
                    },
                    mouseMoveY = function(event){
                        //纵向调整按比例转换为横向比例
                        let newWidth = (event.clientY - posY) / me.target.offsetHeight * me.target.offsetWidth;
                        me.target.style.width = (styleWidth + newWidth / width * valY[index]*100) + '%';
                        me.AttachTo();
                    },
                    mouseMoveAll = function(event){
                        //看谁移动幅度大
                        let x = event.clientX - posX,
                            y = event.clientY - posY,
                            newWidth = (Math.abs(x) > Math.abs(y)?x*valX[index]:y*valY[index]/me.target.offsetHeight * me.target.offsetWidth);
                        me.target.style.width = (styleWidth + newWidth / width *100) + '%';
                        me.AttachTo();
                    },
                    mouseUp = function(){
                        off(me.editor.mainDiv,'mousemove',mouseMoveX);
                        off(me.editor.mainDiv,'mousemove',mouseMoveY);
                        off(me.editor.mainDiv,'mousemove',mouseMoveAll);
                        off(me.doc,'mouseup',mouseUp);
                    };
                if ('0257'.indexOf(index) >= 0){
                    //四角的移动标签
                    on(me.editor.mainDiv,'mousemove',mouseMoveAll);
                }else if(index==='3'||index==='4'){
                    //横向
                    on(me.editor.mainDiv,'mousemove',mouseMoveX);
                }else{
                    //纵向
                    on(me.editor.mainDiv,'mousemove',mouseMoveY);
                }
                on(me.doc, 'mouseup', mouseUp);
            });


            function createButton(title,parent,fn,btn,elm,style){
                let li = createElement(elm||'li','',style);
                li.innerHTML = '<svg class="btnicon" aria-hidden="true"><use xlink:href="#icon-'+(btn?'turnleft':'increase')+'"></use></svg><p style="font-size:14px;color:#333333">'+title+'</p><svg class="btnicon" aria-hidden="true"><use xlink:href="#icon-'+(btn?'turnright':'reduce')+'"></use></svg>';
                on(li.firstChild,'click',function(){
                    fn.call(this,-1);
                });
                on(li.lastChild,'click',function(){
                    fn.call(this,1);
                });
                parent.appendChild(li);
                return li;
            }
            let imageBar = createElement('','imagepanel','','',me.resizer),
                styleBar = createElement('ul','','z-index:2;','',imageBar),
                borderLi = createElement('li','imageborder','','',styleBar);
            borderLi.innerHTML = '<p class="title">边框</p><p class="arrow"></p>';
            on(borderLi,'click',function(){
                let childs = this.childNodes,
                    arrow = childs[1];
                if (arrow.classList.contains('up')){
                    arrow.classList.remove('up');
                    this.lastChild.style.display = 'none';
                }else{
                    arrow.classList.add('up');
                    let borders = 'border,border-left,border-top,border-right,border-bottom',
                        ranges = [];
                    if (childs.length === 2){
                        //创建边框编辑区域
                        let borderBox = createElement('','','position:absolute;top:26px;width:200px;height:130px;border:1px solid #e3e3e3;border-radius:3px;background-color:#fcfcfc;'),
                            borderRange = createElement('','','display:flex;width:100%;height:30px;','',borderBox),
                            borderSize = createElement('','','display:flex;width:100%;height:30px;background-color:#f3f3f3','',borderBox),
                            borderStyle = createElement('','','display:flex;width:100%;height:40px;','',borderBox),
                            borderColor = createElement('','','display:flex;width:100%;height:30px;background-color:#f3f3f3','',borderBox),
                            borderArr = borders.split(','),
                            borderHTML = '';
                        borderArr.forEach((item,i)=>{
                            if (i > 0 && me.target.style[item]){
                                ranges.push(i);
                            }
                            borderHTML += '<div style="width:24px;height:24px;margin:2px 0px 0px 12px;border:1px solid #e3e3e3;'+item+'-color:#555555;"></div>';
                        });
                        borderRange.innerHTML = borderHTML;
                        if (ranges.length == 0){
                            borderRange.firstChild.style.backgroundColor = '#00D1B2';
                        }else{
                            ranges.forEach(item=>{
                                borderRange.childNodes[item].style.backgroundColor = '#00D1B2';
                            });
                        }
                        on(borderBox,'click',function(e){
                            e.stopPropagation();
                        });
                        on(borderRange,'click',function(e){
                            let tag = e.target;
                            if (tag !== borderRange){
                                tag.style.backgroundColor = tag.style.backgroundColor?null:'#00D1B2';
                            }
                        });
                        borderSize.innerHTML = '<p class="borderboxp">宽度</p>';
                        let curWidth = '0px',
                            curStyle = 'solid',
                            curColor = '',
                            setBorder = function (){
                                let nodes = borderRange.childNodes;
                                for(let i=0;i<nodes.length;i++){
                                    if (nodes[i].style.backgroundColor){
                                        me.target.style[borderArr[i]] = curWidth + ' ' + curStyle + ' ' + curColor;
                                        if (i === 0) break;
                                    }
                                }
                            };
                        for (let i=0;i<borderArr.length;i++){
                            let w = me.target.style[borderArr[i]+'-width'];
                            if (w){
                                curWidth = w;
                                break;
                            }
                        }
                        createButton(curWidth,borderSize,function(num){
                            let tag = num > 0?this.previousSibling:this.nextSibling,
                                width = parseInt(tag.innerText) || 0;
                            width += num;
                            if (width < 0){
                                width = 0;
                            }
                            curWidth = width + 'px';
                            tag.innerText = curWidth;
                            setBorder();
                        },false,'div','display:flex;width:max-content;margin-top:6px;');
                        //线型
                        borderStyle.innerHTML = '<p class="borderboxp">线型</p><div style="display:flex;width:160px;height:auto;flex-wrap: wrap;">';
                        let borderStyles = 'none,solid,dotted,hidden,dashed,double,groove,ridge,inset,outset',
                            styleHtml = '';

                        for (let i=0;i<borderArr.length;i++){
                            let s = me.target.style[borderArr[i]+'-style'];
                            if (s){
                                curStyle = s;
                                break;
                            }
                        }
                        borderStyles.split(',').forEach(item=>{
                            styleHtml += '<div data-id="'+item+'" style="width:24px;height:20px;margin-left:4px;'+(item===curStyle?'background-color:#00D1B2;':'')+'"><div style="width:100%; height:10px;border-bottom:2px '+item+' #555555;"></div></div>';
                        });
                        borderStyle.lastChild.innerHTML = styleHtml;
                        on(borderStyle.lastChild,'click',function(e){
                            if (e.target !== this){
                                this.childNodes.forEach(node=>{
                                    node.style.backgroundColor = '';
                                });
                                let tag = e.target.parentNode === this?e.target:e.target.parentNode;
                                tag.style.backgroundColor = '#00D1B2';
                                curStyle = tag.dataset.id;
                                setBorder();
                            }
                        });
                        //颜色
                        let colorHtml = '';
                        for (let i=0;i<borderArr.length;i++){
                            let c = me.target.style[borderArr[i]+'-color'];
                            if (c){
                                curColor = c;
                                break;
                            }
                        }
                        'ffffff,eeece1,1f497d,4f81bd,c0504d,9bbb59,8064a2,4bacc6,f79646'.split(',').forEach(item=>{
                            colorHtml += '<div data-id="2" style="width:13px;height:24px;margin-top:4px;background-color:#'+item+'"></div>';
                        });
                        borderColor.innerHTML = '<p class="borderboxp">颜色</p><div data-id="1" style="width:24px;height:24px;margin:2px 4px;0px;border:1px solid #e3e3e3;border-radius:12px;cursor:pointer;'+(curColor?'backgroundColor:'+curColor:'')+'"></div>'+colorHtml;

                        on(borderColor,'click',function(e){
                            let tag = e.target;
                            if (tag !== this){
                                let id = tag.dataset.id,
                                    elm = borderColor.childNodes[1];
                                if (id == 1){
                                    let pos = this.getBoundingClientRect(),
                                        style = 'left:'+pos.left+'px;top:'+(pos.top+30)+'px;width:230px;height:174px;';;
                                    createPopup(editor,style,colorList(editor),function () {
                                        curColor = elm.style.backgroundColor = this.target.style.backgroundColor;
                                        setBorder();
                                    })
                                }else if (id==2){
                                    elm.style.backgroundColor = curColor = tag.style.backgroundColor;
                                    setBorder();
                                }
                            }
                        });
                        this.appendChild(borderBox);
                    }else{
                        this.lastChild.style.display = 'block';
                    }
                }
            });
            createButton('圆角',styleBar,function(num){
                let radius = parseInt(me.target.style.borderRadius) || 0;
                radius += num * 2;
                me.target.style.borderRadius = ( radius<0?0:radius) + 'px';
            });
            createButton('尺寸',styleBar,function(num){
                let width = me.target.style.width,
                    parsen = '100%';
                if (width && (width.slice(-1)==='%')){
                    parsen = (parseInt(width) + num*2) + '%';
                }else{
                    parsen = ((me.target.offsetWidth / me.editor.body.offsetWidth)*100+num*2) + '%'
                }
                me.target.style.width = parsen;
                me.AttachTo(me.target);
                //me.target.style.height = Math.round(newWidth/width*me.target.offsetHeight) + 'px';
            });
            createButton('阴影',styleBar,function(num){
                let bs = me.target.style.boxShadow,
                    size = bs?parseInt(bs.substr(bs.indexOf('px')+7))+num:1;
                me.target.style.boxShadow = size<0?null:'0px 0px '+size+'px '+size+'px rgba(0,0,0,0.2)';
            });
            createButton('旋转',styleBar,function(num){
                let tf = me.target.style.transform,
                    rotate = tf?parseInt(tf.substr(tf.indexOf('(')+1)):0;
                me.target.style.transform = 'rotate(' + (rotate + num * 2)+'deg)';
            },true);
            let bar = createElement('ul','','display:flex;width:100%;height:30px;','',imageBar),
                btns = [{title:'删除',fun:function(){
                        me.target && me.target.parentNode.removeChild(me.target);
                        me.Hide();
                    }},
                    {title:'重置',fun:function(){
                            me.target && me.target.removeAttribute("style");
                            me.AttachTo(me.target);
                        }},
                    {title:'换图',file:true},
                    {title:'前空行',fun:function(){
                            let obj = createElement('p');
                            createElement('br','','','',obj);
                            me.target && me.target.parentNode.insertBefore(obj,me.target);
                            me.AttachTo(me.target);
                        }},
                    {title:'后空行',fun:function(){
                            let obj = createElement('p');
                            createElement('br','','','',obj);
                            me.target && me.target.parentNode.insertBefore(obj,me.target.nextSibling);
                        }},
                    {title:'上移',fun:function(){
                            if (me.target){
                                let prevNode = me.target.previousSibling;
                                prevNode && me.target.parentNode.insertBefore(me.target,prevNode);
                                me.AttachTo(me.target);
                            }
                        }},
                    {title:'下移',fun:function(){
                            me.target && me.target.nextSibling && me.target.parentNode.insertBefore(me.target,me.target.nextSibling.nextSibling);
                            me.AttachTo(me.target);
                        }},
                    {title:'自适应',fun:function(){
                            me.target && (me.target.style.width='100%');
                            me.AttachTo(me.target);
                        }}];
            btns.forEach(item=>{
                let btn = createElement('li','btn','width:max-content;margin:0px 4px 0px 4px;');
                if (item.file){
                    if (editor.wx){
                        //微信上传图片
                        btn.innerHTML = '<p>'+item.title+'</p>';
                        on(btn,'click',()=>{
                            wx.chooseImage({
                                count: 1,
                                sizeType: ['original', 'compressed'],
                                sourceType: ['album', 'camera'],
                                success (res) {
                                    me.target.src = res.localIds[0];
                                    me.AttachTo(me.target);
                                }
                            })
                        });
                    }else{
                        btn.innerHTML = '<p>'+item.title+'</p><input type="file" accept="image/*" style="position: absolute;width: 100%;height: 100%;left: 0;top: 0;opacity: 0;"/>';
                        on(btn.childNodes[1],'change',function(e) {
                            let file = e.target.files[0];
                            if (me.target && file) {
                                const reader = new FileReader();
                                reader.onload = (event) => {
                                    me.target.src = event.target.result;
                                    me.target.onload = function () {
                                        me.AttachTo(me.target);
                                        me.target.onload = null;
                                    }
                                };
                                reader.readAsDataURL(file);
                            }
                        });
                    }
                }else{
                    btn.innerText = item.title;
                    on(btn,'click',item.fun);
                }
                bar.appendChild(btn);
            });
            editor.mainDiv.appendChild(me.resizer);
            me.target = null;
            me.display = false;
            me.startPos = {x: 0, y: 0};
            me.targetRect = {width:0,height:0};
        },
        StyleList: function(element){
        },
        AttachTo: function (targetObj,change) {
            targetObj = targetObj || this.target;
            let me = this,
                resizer = me.resizer,
                doc = me.editor.iframe.contentDocument || me.editor.iframe.contentWindow.document,
                tagPos = targetObj.getBoundingClientRect();
            resizer.style.top = (tagPos.top) + 'px';
            resizer.style.left = (tagPos.left) + 'px';
            resizer.style.width = targetObj.offsetWidth + 'px';
            resizer.style.height = targetObj.offsetHeight + 'px';
            if (editor.mainDiv.offsetWidth > resizer.lastChild.offsetWidth){
                //调整按钮组横向位置
                let left = editor.mainDiv.offsetWidth - tagPos.left - resizer.lastChild.offsetWidth - 10;
                resizer.lastChild.style.left = (left>0?0:left)+'px';
            }else{
                resizer.lastChild.style.left = -tagPos.left + 'px';
            }
            if (!me.display){
                me.cover.style.display = null;
                resizer.style.display = null;
                me.display = true;
                me.editor.iframe.contentDocument.body.onscroll = function(){
                    let top = targetObj.offsetTop -  doc.documentElement.scrollTop;
                    if (top > 0){
                        resizer.style.top = (me.editor.iframe.parentNode.offsetTop + top - 2) + 'px';
                    }else{
                        me.Hide();
                    }
                }
            }
            change && me.StyleList(targetObj);
        },
        Hide: function(){
            this.cover.style.display = 'none';
            this.resizer.style.display = 'none';
            this.display = false;
            this.editor.iframe.contentDocument.body.onscroll = null;
        }
    };
    /*图文素材库编辑对象
    * 作者：蒲子明，最后更新时间：20201019
    * V1.0.0
    */
    function Section(editor) {
        this.editor = editor;
        this.target = null;
        this.display = false;
        this.colors = {};
        this.Init();
    }
    Section.prototype = {
        Init: function () {
            let me = this;
            me.sectionBar = createElement('','sectionbar');
            //选择框
            let selectedBox = createElement('','','position:relative;height:0px;margin-top:-4px;border-top:2px dashed #dadadc','',me.sectionBar),
                boxLeft = createElement('','','position:absolute;left:0px;bottom:0px;width:0px;border-left:2px dashed #dadadc','',selectedBox);
            createElement('','','position:absolute;top:0px;left:0px;height:0px;border-bottom:2px dashed #dadadc','',boxLeft);
            createElement('','','position:absolute;right:0px;bottom:0px;width:0px;border-left:2px dashed #dadadc','',selectedBox);
            me.colorBar = createElement('ul','','','',me.sectionBar);

            let bar = createElement('ul','','','',me.sectionBar),
                btns = [{title:'删除',fun:function(){
                        me.target && me.target.parentNode.removeChild(me.target) && me.Hide();
                    }},
                    {title:'重置',fun:function(){
                            let nodes = me.colorBar.childNodes;
                            for(let i=0,len=nodes.length;i<len;i++){
                                let bg = nodes[i].dataset.bg;
                                if (bg && me.colors[bg]){
                                    for (let key in me.colors[bg]){
                                        me.colors[bg][key].forEach(obj=>{
                                            obj.style[key] = bg;
                                        });
                                    }
                                    nodes[i].style.backgroundColor = bg;
                                    nodes[i].dataset.bg = null;
                                }
                            }
                        }},
                    {title:'前空行',fun:function(){
                            let obj = createElement('p');
                            createElement('br','','','',obj);
                            me.target && me.target.parentNode.insertBefore(obj,me.target);
                            me.AttachTo(me.target);
                        }},
                    {title:'后空行',fun:function(){
                            let obj = createElement('p');
                            createElement('br','','','',obj);
                            me.target && me.target.parentNode.insertBefore(obj,me.target.nextSibling);
                        }},
                    {title:'上移',fun:function(){
                            if (me.target){
                                let prevNode = me.target.previousSibling;
                                prevNode && me.target.parentNode.insertBefore(me.target,prevNode);
                                me.AttachTo(me.target);
                            }
                        }},
                    {title:'下移',fun:function(){
                            me.target && me.target.nextSibling && me.target.parentNode.insertBefore(me.target,me.target.nextSibling.nextSibling);
                            me.AttachTo(me.target);
                        }}];
            btns.forEach(item=>{
                let btn = createElement('li','sectionbtn');
                btn.innerText = item.title;
                on(btn,'click',item.fun);
                bar.appendChild(btn);
            });
            me.editor.mainDiv.appendChild(me.sectionBar);
            on(me.editor.document,'scroll',()=>{
                if (me.target && me.display){
                    let tagPos = me.target.getBoundingClientRect();
                    me.sectionBar.style.top = (tagPos.top+tagPos.height) + 'px';
                }
            });
        },
        ColorList: function(element){
            //边框、背景、字体颜色列表
            let me = this;
            element = element || me.target;
            me.colors = {};
            function initColors(co,style){
                me.colors[co] = me.colors[co] || {};
                me.colors[co][style] = me.colors[co][style] || [];
            }
            function getColor(elm){
                let boders = ['','Top','Right','Bottom','Left'];
                for (let i=0,len=boders.length;i<len;i++){
                    if (elm.style && parseInt(elm.style['border'+boders[i]+'Width'])){
                        let style = 'border'+boders[i]+'Color',
                            color = elm.style[style];
                        if (color){
                            initColors(color,style);
                            me.colors[color][style].push(elm);
                            if (i===0) break;
                        }
                    }
                }
                if (elm.style){
                    let bg = 'backgroundColor',
                        color = elm.style[bg];
                    if (color){
                        initColors(color,bg);
                        me.colors[color][bg].push(elm);
                    }
                    bg = 'boxShadow';
                    color = elm.style[bg];
                    if (color){
                        //阴影颜色，需要判断两种颜色方法
                        let pos = color.indexOf('#'),
                            end = 0;
                        if (pos >= 0){
                            end = color.indexOf(';',pos);
                            if (end > pos){
                                let c = utils.trim(color.substring(pos,end));
                                initColors(c,bg);
                                me.colors[c][bg].push({elm,val:color.replace(c,'')});
                            }
                        }else{
                            pos = color.indexOf('rgb');
                            if (pos >= 0){
                                end = color.indexOf(')',pos);
                                if (end > pos){
                                    let c = utils.trim(color.substring(pos,end+1));
                                    initColors(c,bg);
                                    me.colors[c][bg].push({elm,val:color.replace(c,'')});
                                }
                            }
                        }
                    }
                }
            }
            function setColor(color,value){
                let colors = me.colors[color];
                for (let key in colors){
                    colors[key].forEach(obj=>{
                        if (key === 'boxShadow'){
                            //console.log(color,value,obj.elm,obj.val);
                            obj.elm.style[key] = value + obj.val;
                        }else{
                            obj.style[key] = value;
                        }
                    });
                }
            }
            function find(elm) {
                let next = elm;
                while(next){
                    getColor(next);
                    find(next.firstChild);
                    next = next.nextSibling;
                }
            }
            if (element){
                getColor(element);
                find(element.firstChild);
            }
            //遍历colors，配置颜色li
            let li = me.colorBar.firstChild,
                hasLi = true;
            for (var key in me.colors){
                if (hasLi && li) {
                    li.style.backgroundColor = key;
                    li.style.display = 'block';
                    li.dataset.bg = '';
                    li = li.nextSibling;
                }else{
                    li = createElement('li','sectioncolor','background-color:'+key,'',me.colorBar);
                    on(li,'mouseover',function(){
                        let colorValue = 'transparent';
                        this.timer = setInterval(()=>{
                            let color = this.style.backgroundColor;
                            setColor(color,colorValue);
                            colorValue = colorValue===color?'transparent':color;
                        },800);
                        on(this,'mouseout', function(){
                            clearInterval(this.timer);
                            (colorValue !== 'transparent') && setColor(this.style.backgroundColor,colorValue)
                            this.timer = null;
                            this.onmouseout = null;
                        });
                    });

                    on(li,'click',function(){
                        let that = this,
                            bgcolor = this.dataset.bg || this.style.backgroundColor,
                            pos = this.getBoundingClientRect(),
                            style = 'left:'+pos.left+'px;top:'+(pos.top+30)+'px;width:230px;height:174px;';
                        createPopup(me.editor,style,colorList(me.editor),function () {
                            let color = this.target.style.backgroundColor;
                            if (!that.dataset.bg && color !== bgcolor){
                                that.dataset.bg = bgcolor;
                            }
                            setColor(bgcolor,color);
                            that.style.backgroundColor = color;
                        })
                    });
                    hasLi = false;
                }
            }
            while(hasLi && li){
                li.style.display='none';
                li = li.nextSibling;
            }
        },
        AttachTo: function (targetObj,change) {
            let me = this;
            me.target = targetObj;
            if (change){
                me.ColorList(targetObj);
                if (editor.popup){
                    remove(editor.popup);
                    editor.popup = null;
                }
            }
            if (utils.isEmptyObject(me.colors)){
                me.Hide();
                return false;
            }
            let sectionBar = me.sectionBar,
                tagPos = targetObj.getBoundingClientRect();

            sectionBar.style.top = (tagPos.top + tagPos.height+2) + 'px';
            sectionBar.firstChild.style.width = me.editor.iframe.offsetWidth - 2 + 'px';
            sectionBar.firstChild.firstChild.firstChild.style.width = me.editor.iframe.offsetWidth - 4 + 'px';

            sectionBar.firstChild.firstChild.style.height = sectionBar.firstChild.lastChild.style.height = (tagPos.height + 2) + 'px';
            if (!me.display){
                sectionBar.style.display = null;
                me.display = true;
            }
            return true;
        },
        Hide: function(){
            if (editor.popup){
                remove(editor.popup);
                editor.popup = null;
            }
            this.sectionBar.style.display = 'none';
            this.display = false;
            this.editor.body.onscroll = null;
        }
    };
})();